package aml.runtime;

import java.util.ArrayList;
import java.util.List;

import aml.parse.ParseNode;

public class Context extends Value {

	public Context() {
		slots.put("method", new Method() {
			@Override
			public Value apply(Context ctx, Value[] args) {
				if (args[0] instanceof Tuple) {
					Tuple t = (Tuple) args[0];
					List<ParseNode> nodes = t.getChildren();
					final int argc = nodes.size() - 1;
					final List<String> paramNames = new ArrayList<String>();
					for (int i = 0; i < argc; i++) {
						paramNames.add(nodes.get(i).eref(t.getContext()).toString());
					}
					final ParseNode body = nodes.get(argc);
					return new Method() {
						@Override
						public Value apply(Context ctx, Value[] args) {
							if (args[0] instanceof Tuple) {
								Context context = (Context) ctx.clone();
								Tuple t = (Tuple) args[0];
								List<ParseNode> nodes = t.getChildren();
								while (nodes.size() < argc) {
									nodes.add(null);
								}
								for (int i = 0; i < argc; i++) {
									context.setSlot(paramNames.get(i), nodes.get(i).eval(ctx));
								}
								return body.eval(context);
							}
							return null;
						}
					};
				}
				return null;
			}
		});
		
		slots.put("return", new Method() {
			@Override
			public Value apply(Context ctx, Value[] args) {
				Value ret = null;
				if (args[0] instanceof Tuple) {
					Tuple t = (Tuple) args[0];
					List<ParseNode> nodes = t.getChildren();
					for (int i = 0; i < nodes.size(); i++) {
						ret = nodes.get(i).eval(t.getContext());
					}
				}
				ctx.setReturnFlag();
				return ret;
			}
		});
	}
	
	private boolean returnFlag = false;
	
	protected void setReturnFlag() {
		returnFlag = true;
	}

	public boolean getReturnFlag() {
		return returnFlag;
	}

	public void clearReturnFlag() {
		returnFlag = false;
	}
	
	private boolean isTopLevel = true;
	
	public void setTopLevel() {
		isTopLevel = true;
	}
	
	public boolean isTopLevel() {
		return isTopLevel;
	}
	
	public void clearTopLevel() {
		isTopLevel = false;
	}

	@Override
	public ValueNum toNum() {
		return new ValueNum(slots.size());
	}

}